package cn.ac.cintcm.prespring.cluster;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import cn.ac.cintcm.prespring.util.IndexFile;

public class CalSimilarity {
    
    
    public static void main(String[] args) throws IOException {
        CalSimilarity cs = new CalSimilarity(new IndexFile("PRES_FJ_ZYS.txt"));
        Similarity s = cs.getSimilarElements(0.7f, "036955", null);
        System.out.println(s.getTime());
        for (Integer e : s.getSimilarElements()) {
            System.out.println(e + ",");
        }
    }
    
    private float ratio = 2/3f;
    //开始扫描的下限
    private int start = 1;
    //开始扫描的上限
    private int end = 1;
    
    private IndexFile index;
    
    public CalSimilarity(IndexFile index) {
        this.index = index;
    }
    /**
     * 获取在一定的集合内与参考元素相似的其它集合元素
     * @param ratio 相似度
     * @param id 参考元素的编号
     * @return 与参考元素相似的元素集合
     */
    public Similarity getSimilarElements(float ratio, String id, List<Integer> sets) {
        Similarity sim = new Similarity();
        sim.setId(id);
        Integer integerID = Integer.valueOf(id);
        sim.setRatio(ratio);
        long begin = System.currentTimeMillis();
        if (index != null) {
            List<Integer> elements = index.getIdListIndex().get(integerID);
            if (elements != null) {
                calculateScanRange(ratio, elements.size());
                HashMap<Integer, List<Integer>> sizeIndex = index.getSizeListIndex();
                HashMap<Integer, List<Integer>> idIndex = index.getIdListIndex();
                List<Integer> similarElements = new ArrayList<Integer>();
                for (int i = start; i <= end; i++) {
                    List<Integer> compare = sizeIndex.get(i);
                    if (compare != null) {
                        for (Integer compareElement : compare) {
                            if (isSimilar(idIndex.get(compareElement), elements, ratio)) {
                                similarElements.add(compareElement);
                            }
                        }
                    }
                }
                similarElements.remove(integerID);
                sim.setSimilarElements(similarElements);
            }
        }
        long end = System.currentTimeMillis();
        sim.setTime(end - begin);
        return sim;
        
    }

    private void calculateScanRange(float ratio, int size) {
        float requiredRatio = ratio;
        if (requiredRatio < this.ratio) {
            requiredRatio = this.ratio;
        }
        start = (int)Math.ceil(ratio * size /(2 - ratio));
        end = (int) (2 * size/requiredRatio) - size;
    }
    
    public static boolean isSimilar(List<Integer> a, List<Integer> b, float simRate) {
        boolean value = false;
        if (a != null && b != null && a.size() >0 && b.size() > 0) {
            int intersection = join(a, b);
            float rate = 2 * (float) intersection / (float) (a.size() + b.size());
            if (rate >= simRate) {
                value = true;
            }
        }
        return value;
    }

    private static int join(List<Integer> a, List<Integer> b) {
        int intersection = 0;
        int aValue = a.get(0);
        int bValue = b.get(0);
        int ai = 0;
        int bj = 0;
        while (true) {
            if (aValue == bValue) {
                intersection++;
                ai++;
                bj++;
            } else if (aValue < bValue) {
                ai++;
            } else {
                bj++;
            }
            if (ai == a.size() || bj == b.size()) {
                break;
            }
            aValue = a.get(ai);
            bValue = b.get(bj);
        }
        return intersection;
    }

}
